/**
 * @Descrition:
 * @Param:
 * @Param:
 * @Return:
 * @Auditor :ziliang.zhou
 * @Vesion:1.0.0
 */
package com.sunyard.utils.wxv3Util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.*;

import cn.hutool.http.HttpResponse;
import com.sunyard.constant.ErrMessageConst;
import com.sunyard.exception.IllegalOperationException;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;

//import static org.eclipse.jetty.util.LazyList.remove;

/**
 * HttpUrl工具类
 *
 * @author ziliang.zhou
 * @version 1.0 2020年9月9日
 */
@Slf4j
public class HttpUrlUtil {

    public static String POST = "POST";

    public static String GET = "GET";

    public static String SCHEMA = "WECHATPAY2-SHA256-RSA2048";

    public static String wxCertUrl = "https://api.mch.weixin.qq.com/v3/certificates";


    /**
     * POST请求  提交活动报名
     *
     * @param url              请求url
     * @param body             请求body
     * @param apilientCertPath 平台证书
     * @param apiclientKeyPath 微信私钥路径
     * @param paramMap         请求信息
     * @param merchantId       微信服务商户号
     * @param serialNo         微信平台证书序列号
     * @param hostname         代理地址
     * @param port             代理端口号
     * @param proxy            是否使用代理
     */
    public static WxHttpResponse sendPost(String url, String body, String apilientCertPath, String apiclientKeyPath, Map<String, Object> paramMap, String merchantId, String serialNo, String hostname, String port, String proxy) {
        // 获取微信平台商户证书序列号
        String authorization = getToken(POST, url, body, merchantId, apilientCertPath, apiclientKeyPath);
        log.info("签名信息是：" + authorization);
        WxHttpResponse response = new WxHttpResponse();
        Map<String, String> headers = getHeaders(authorization, serialNo);
        boolean b = Boolean.parseBoolean(proxy);
        HttpResponse httpResponse = null;
        if (b) {
            log.info("代理信息:host=" + hostname + ",port=" + port);
            Proxy proxy1 = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostname, Convert.toInt(port)));
            httpResponse = HttpRequest.post(url)
                    .addHeaders(headers)
                    .body(body)
                    .setProxy(proxy1)
                    .execute();
        } else {
            httpResponse = HttpRequest.post(url)
                    .addHeaders(headers)
                    .body(body)
                    .execute();
        }
        if (ObjectUtil.isNull(httpResponse)) {
            throw new IllegalOperationException("微信请求异常");
        }
        response.setBody(httpResponse.body());
        response.setStatus(httpResponse.getStatus());
        return response;
    }

    /**
     * get请求
     */
    public static WxHttpResponse sendGet(String url, String body, String apilientCertPath, String apiclientKeyPath, String merchantId, String serialNo, String hostname, String port, String proxy) {
        try {
            log.info("请求地址:{}", url);
            log.info("请求body:{}", body);
            log.info("请求merchantId:{}", merchantId);
            log.info("请求serialNo:{}", serialNo);
            String authorization = getToken(GET, url, body, merchantId, apilientCertPath, apiclientKeyPath);
            log.info("签名信息是：" + authorization);
            WxHttpResponse response = new WxHttpResponse();
            Map<String, String> headers = getHeaders(authorization, serialNo);
            boolean a = Boolean.getBoolean(proxy);
            HttpResponse httpResponse = null;
            if (a) {
                Proxy proxy1 = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostname, Convert.toInt(port)));
                httpResponse = HttpRequest.get(url)
                        .addHeaders(headers)
                        .form(null)
                        .setProxy(proxy1)
                        .execute();
            } else {
                httpResponse = HttpRequest.get(url)
                        .addHeaders(headers)
                        .form(null)
                        .execute();
            }
            if (ObjectUtil.isNull(httpResponse)) {
                throw new IllegalOperationException("微信V3接口未返回");
            }
            response.setBody(httpResponse.body());
            response.setStatus(httpResponse.getStatus());
            return response;
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            WxHttpResponse wxHttpResponse = new WxHttpResponse();
            wxHttpResponse.setCode(ErrMessageConst.SYSTEM_ERROR);
            wxHttpResponse.setMessage(e.getMessage());
            return wxHttpResponse;
        }
    }

    /**
     * get请求 获取微信平台证书
     */
    public static WxHttpResponse sendGet(String apilientCertPath, String apiclientKeyPath, String merchantId) {
        try {
            String authorization = getToken(GET, wxCertUrl, "", merchantId, apilientCertPath, apiclientKeyPath);
            System.out.println("签名信息是：" + authorization);
            WxHttpResponse response = new WxHttpResponse();
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", ContentType.JSON.toString());
            headers.put("Accept", ContentType.JSON.toString());
            headers.put("Authorization", authorization);
            //headers.put("User-Agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0");
            Map<String, Object> paramMap = null;
            HttpResponse httpResponse = HttpRequest.get(wxCertUrl)
                    .addHeaders(headers)
                    .form(paramMap)
                    .execute();
            response.setBody(httpResponse.body());
            response.setStatus(httpResponse.getStatus());
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static Map<String, String> getHeaders(String authorization, String serialNumber) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json;charset=UTF-8");
        if (StrUtil.isNotEmpty(serialNumber)) {
            headers.put("Wechatpay-Serial", serialNumber);
        }
        headers.put("Accept", ContentType.JSON.toString());
        headers.put("Authorization", authorization);
        headers.put("user-agent", "application/json");
        return headers;
    }


    /**
     * 获取加密串
     *
     * @param method
     * @param url
     * @param body
     * @return
     */
    public static String getToken(String method, String url, String body, String merchantId, String applientCert, String apiclientKeyPath) {
        String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");
        long timestamp = System.currentTimeMillis() / 1000;
        HttpUrl httpUrl = HttpUrl.parse(url);
        if (ObjectUtil.isNull(httpUrl)) {
            throw new IllegalOperationException("请求url地址错误");
        }
        String message = buildMessage(method, httpUrl, timestamp, nonceStr, body);
        String signature = null;
        String certificateSerialNo = null;
        try {
            signature = sign(message.getBytes("utf-8"), apiclientKeyPath);
            certificateSerialNo = CertUtil.getSerialNo(applientCert);
            log.info("certificateSerialNo:" + certificateSerialNo);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            throw new IllegalOperationException("加密异常");
        }

        return SCHEMA + " mchid=\"" + merchantId + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + certificateSerialNo + "\","
                + "signature=\"" + signature + "\"";
    }

    /**
     * 得到签名字符串
     */
    public static String sign(byte[] message, String privateKeys) throws Exception {
        Signature sign = Signature.getInstance("SHA256withRSA");
        PrivateKey privateKey = CertUtil.getPrivateKey(privateKeys);
        sign.initSign(privateKey);
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    public static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
        System.out.println(url.encodedPath());
        String canonicalUrl = url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
            //  }else {
            //    throw new IllegalOperationException("url地址错误");
        }
        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }


}